<template>
  <div class="flow-chart">
    <div class="stencil" ref="stencilContainer"></div>
    <div class="graph" ref="container"></div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { Graph, Shape, Addon } from '@antv/x6'
import '@antv/x6-vue-shape'

const container = ref<HTMLElement | null>(null)
const stencilContainer = ref<HTMLElement | null>(null)

// 定义节点和边的样式
const initGraph = () => {
  if (!container.value || !stencilContainer.value) return

  // 创建主画布
  const graph = new Graph({
    container: container.value,
    width: 800,
    height: 600,
    grid: {
      visible: true,
      type: 'mesh',
      size: 10,
      args: {
        color: '#e5e5e5',
      },
    },
    connecting: {
      router: 'manhattan',
      connector: {
        name: 'rounded',
        args: {
          radius: 8,
        },
      },
      anchor: 'center',
      connectionPoint: 'anchor',
      allowBlank: false,
      snap: {
        radius: 20,
      },
      createEdge() {
        return new Shape.Edge({
          attrs: {
            line: {
              stroke: '#5F95FF',
              strokeWidth: 1,
              targetMarker: {
                name: 'classic',
                size: 8,
              },
            },
          },
          router: {
            name: 'manhattan',
          },
          zIndex: 0,
        })
      },
    },
    highlighting: {
      magnetAvailable: {
        name: 'stroke',
        args: {
          padding: 4,
          attrs: {
            strokeWidth: 4,
            stroke: '#52c41a',
          },
        },
      },
    },
    mousewheel: {
      enabled: true,
      modifiers: ['ctrl', 'meta'],
    },
    interacting: {
      nodeMovable: true,
      edgeMovable: false,
      magnetConnectable: true,
    },
  })

  // 注册节点
  // 开始节点
  Graph.registerNode('flow-start', {
    inherit: 'circle',
    width: 80,
    height: 40,
    attrs: {
      body: {
        stroke: '#5F95FF',
        strokeWidth: 1,
        fill: '#ffffff',
      },
      text: {
        fontSize: 12,
        fill: '#262626',
      },
    },
    ports: {
      groups: {
        top: {
          position: 'top',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        right: {
          position: 'right',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        bottom: {
          position: 'bottom',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        left: {
          position: 'left',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
      },
      items: [
        { group: 'top' },
        { group: 'right' },
        { group: 'bottom' },
        { group: 'left' },
      ],
    },
  })

  // 过程节点
  Graph.registerNode('flow-process', {
    inherit: 'rect',
    width: 100,
    height: 40,
    attrs: {
      body: {
        stroke: '#5F95FF',
        strokeWidth: 1,
        fill: '#ffffff',
      },
      text: {
        fontSize: 12,
        fill: '#262626',
      },
    },
    ports: {
      groups: {
        top: {
          position: 'top',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        right: {
          position: 'right',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        bottom: {
          position: 'bottom',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        left: {
          position: 'left',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
      },
      items: [
        { group: 'top' },
        { group: 'right' },
        { group: 'bottom' },
        { group: 'left' },
      ],
    },
  })

  // 决策节点
  Graph.registerNode('flow-decision', {
    inherit: 'polygon',
    width: 80,
    height: 40,
    attrs: {
      body: {
        refPoints: '0,10 10,0 20,10 10,20',
        strokeWidth: 1,
        stroke: '#5F95FF',
        fill: '#ffffff',
      },
      text: {
        fontSize: 12,
        fill: '#262626',
      },
    },
    ports: {
      groups: {
        top: {
          position: 'top',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        right: {
          position: 'right',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        bottom: {
          position: 'bottom',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        left: {
          position: 'left',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
      },
      items: [
        { group: 'top' },
        { group: 'right' },
        { group: 'bottom' },
        { group: 'left' },
      ],
    },
  })

  // 数据节点
  Graph.registerNode('flow-data', {
    inherit: 'polygon',
    width: 80,
    height: 40,
    attrs: {
      body: {
        refPoints: '10,0 40,0 30,20 0,20',
        strokeWidth: 1,
        stroke: '#5F95FF',
        fill: '#ffffff',
      },
      text: {
        fontSize: 12,
        fill: '#262626',
      },
    },
    ports: {
      groups: {
        top: {
          position: 'top',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        right: {
          position: 'right',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        bottom: {
          position: 'bottom',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        left: {
          position: 'left',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
      },
      items: [
        { group: 'top' },
        { group: 'right' },
        { group: 'bottom' },
        { group: 'left' },
      ],
    },
  })

  // 创建 Stencil
  const stencil = new Addon.Stencil({
    title: '流程图',
    target: graph,
    stencilGraphWidth: 200,
    stencilGraphHeight: 600,
    collapsable: true,
    search: false,
    groups: [
      {
        title: '基础流程图',
        name: 'basic',
        graphHeight: 200,
        layoutOptions: {
          columns: 1,
          marginX: 20,
          marginY: 10,
        },
      },
      {
        title: '系统设计图',
        name: 'system',
        graphHeight: 200,
        layoutOptions: {
          columns: 1,
          marginX: 20,
          marginY: 10,
        },
      },
    ],
  })

  stencilContainer.value.appendChild(stencil.container)

  // 基础流程图节点
  const start = graph.createNode({
    shape: 'flow-start',
    label: '开始',
  })

  const process = graph.createNode({
    shape: 'flow-process',
    label: '过程',
  })

  const decision = graph.createNode({
    shape: 'flow-decision',
    label: '决策',
  })

  const data = graph.createNode({
    shape: 'flow-data',
    label: '数据',
  })

  // 系统设计图节点
  const systemStart = graph.createNode({
    shape: 'flow-start',
    label: '系统开始',
  })

  const systemProcess = graph.createNode({
    shape: 'flow-process',
    label: '系统过程',
  })

  const systemDecision = graph.createNode({
    shape: 'flow-decision',
    label: '系统决策',
  })

  const systemData = graph.createNode({
    shape: 'flow-data',
    label: '系统数据',
  })

  // 加载节点到对应的组
  stencil.load([start, process, decision, data], 'basic')
  stencil.load([systemStart, systemProcess, systemDecision, systemData], 'system')

  return graph
}

onMounted(() => {
  initGraph()
})
</script>

<style scoped>
.flow-chart {
  display: flex;
  width: 100%;
  height: 100vh;
  background-color: #fff;
}

.stencil {
  width: 200px;
  height: 100%;
  border-right: 1px solid #ddd;
  overflow: hidden;
}

.graph {
  flex: 1;
  height: 100%;
}

:deep(.x6-widget-stencil) {
  background-color: #fff;
  height: 100%;
  overflow: hidden;
}

:deep(.x6-widget-stencil-title) {
  background-color: #f7f9fb;
  border-color: #ddd;
  text-align: left;
  padding: 8px 12px;
  font-size: 14px;
  font-weight: 500;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid #ddd;
}

:deep(.x6-widget-stencil-title-text) {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-right: 8px;
}

:deep(.x6-widget-stencil-title-icon) {
  cursor: pointer;
  transition: transform 0.2s;
  flex-shrink: 0;
}

:deep(.x6-widget-stencil-title-icon.collapsed) {
  transform: rotate(-90deg);
}

:deep(.x6-widget-stencil-group-title) {
  background-color: #f7f9fb;
  text-align: left;
  padding: 8px 12px;
  font-size: 12px;
  color: #666;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid #ddd;
}

:deep(.x6-widget-stencil-group-title-text) {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-right: 8px;
}

:deep(.x6-widget-stencil-group-title-icon) {
  cursor: pointer;
  transition: transform 0.2s;
  flex-shrink: 0;
}

:deep(.x6-widget-stencil-group-title-icon.collapsed) {
  transform: rotate(-90deg);
}

:deep(.x6-widget-stencil-group) {
  border-bottom: 1px solid #ddd;
}

:deep(.x6-widget-stencil-group-content) {
  padding: 8px;
}

:deep(.x6-widget-stencil-group-header) {
  cursor: pointer;
  display: flex;
  align-items: center;
  padding: 8px 12px;
}

:deep(.x6-widget-stencil-group-header:hover) {
  background-color: #f0f0f0;
}

:deep(.x6-widget-stencil-group-header-icon) {
  margin-right: 4px;
  transition: transform 0.2s;
}

:deep(.x6-widget-stencil-group-header-icon.collapsed) {
  transform: rotate(-90deg);
}
</style> 